
package com.example.myhelloworld.client;

import java.lang.Character;
/*
*An evaluator has one eval method that takes a formula and outputs an answer by first lexing and then parsing
*the input, and thereafter constructing an expression tree and evaluating it. Can be used with + - * / ( ).
*/
public class Evaluator {
  static final char integer = '0';
  static int token;
  static int tokval;
  static int c;
  static int position = 0;
  static String formula;

  public static int eval(String form) {
    token = 0; tokval = 0; c = 0; position = 0;
    formula = form;
    c = getChar();
    getToken();
    int result = -1;
    for (;;) {
      Expr e = expr();
      result = e.eval();
      //System.out.println("Result = " + result);
      if (token!=0) {
        System.out.println("Syntax error in formula!");
      } else {
        return result;
      }
    }
  }

  static int getChar() {
    if (position == formula.length()) return -1;
    return formula.charAt(position++);
  }

  static boolean isMySpace(char sp){
	  if ((sp==' ') || (sp=='\t') || (sp == '\n')){
		  return true;
	  }
	  return false;
  }
  
  static void getToken() {
    while (isMySpace(((char)c))) {
      c = getChar();
    }

    if (c<0) {
      token = 0;
      System.out.println("Done parsing formula.");
      return;
    }
    switch (c) {
      case '+' :
      case '-' :
      case '*' :
      case '/' :
      case '(' :
      case ')' : token = c;
        c = getChar();
        return;
      default  :
        if (Character.isDigit((char)c)) {
          int n = 0;
          do {
            n = 10*n + (c - '0');
            c = getChar();
          } while (Character.isDigit((char)c));
          tokval = n;
          token  = integer;
          return;
        }
      }
    System.out.println("Invalid character in formula: "+c);
  }

  static Expr expr() {
    Expr e = term();

    for (;;) {
      if (token=='+') {
        getToken();
        e = new BinExpr('+',e,term());
      } else if (token=='-') {
        getToken();
        e = new BinExpr('-',e,term());
      } else {
        return e;
      }
    }
  }

  static Expr term() {
    Expr t = atom();

    for (;;) {
      if (token=='*') {
        getToken();
        t = new BinExpr('*',t,atom());
      } else if (token=='/') {
        getToken();
        t = new BinExpr('/',t,atom());
      } else {
        return t;
      }
    }
  }

  static Expr atom() {
    if (token==integer) {
      int f = tokval;
      getToken();
      return new IntExpr(f);
    } else if (token=='(') {
      getToken();
      Expr e = expr();
      if (token==')') {
        getToken();
      } else {
        System.out.println("Missing ) in formula!");
      }
      return e;
    } else {
      System.out.println("Syntax error in atom!");
    }
    return null; /* not used */
  }

  //The expression tree, as inner classes:
  abstract static class Expr {
    abstract int eval();
  }

  static class IntExpr extends Expr {
    private int value;

    IntExpr(int value) {
      this.value = value;
    }

    int eval() {
      return value;
    }
  }

  static class BinExpr extends Expr {
    private char op;
    private Expr left;
    private Expr right;

    BinExpr(char op, Expr left, Expr right) {
      this.op    = op;
      this.left  = left;
      this.right = right;
    }

    int eval() {
      int l = left.eval();
      int r = right.eval();
      switch (op) {
        case '+' : return l + r;
        case '-' : return l - r;
        case '*' : return l * r;
        case '/' : return l / r;
      }
      return 0; /* not used */
    }
  }
}